/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "dma.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "string.h"
#include "stdint.h"
#include "stdlib.h"

#include "usrList.h"
#include "usrAtHandle.h"
#include "usrError.h"
#include "usrConfig.h"

#include "mqtt.h"
#include "mqtt_pal.h"

#include "cJSON.h"

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
#if AT_TEST
uint8_t reviceDat[200] = "AT\\r\\n";
uint8_t reviceTmp;
uint8_t RxCounter = 0;
#endif

uint8_t reviceDmaDat[USR_RX_DMA_LEN_MAX];

uint8_t timer2Flag  = 0;
uint8_t timer3Flag  = 0;

static struct mqtt_client client;

static uint8_t usrMqttStatus = 0;

Queue usrListTx;
Queue usrListRx;

uint8_t sendbuf[2048]; /* sendbuf should be large enough to hold multiple whole mqtt messages */
uint8_t recvbuf[1024]; /* recvbuf should be large enough any whole mqtt message expected to be received */

char test[] = "{                  \
    \"id\": \"213\",                    \
    \"version\": \"1.0\",               \
    \"params\": {                     \
        \"CurrentHumidity\":88.8,     \
        \"CurrentTemperature\":66.6   \
    }                               \
  }";  

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
uint8_t usrAddCmd(char* p_dat, int len);
void usrSendCmd(void);
uint8_t usrAddAck(char* p_dat, int len);
uint8_t usrHandleAck(char* p_dat, int* len);
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
#if AT_TEST
void app_uart_cb(UART_HandleTypeDef *huart)
{
	if(huart->Instance == USART1)
	{
		/* Read one byte from the receive data register */
    reviceDat[RxCounter++] = reviceTmp;
//		HAL_UART_Transmit(&huart1, (uint8_t*) &Rx_Temp,1,0xFF);
		HAL_UART_Receive_IT(&huart1,(uint8_t*)&reviceTmp,1);				// ?????????????????
	}
}

void USER_UART_IDLECallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance == USART1)
	{
		if(RESET != __HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE))
		{
			USART1->DR;													
      HAL_UART_Transmit_DMA(&huart3, reviceDat, RxCounter);
			
			// __HAL_UART_CLEAR_IDLEFLAG(huart);			
			RxCounter = 0;
		}
	}
}

void USER_UART3_IDLECallback(UART_HandleTypeDef *huart)
{
	
}

void app_uart3_tx_cb(UART_HandleTypeDef *huart)
{
	if(huart->Instance == USART3)
	{
		if(RESET != __HAL_UART_GET_FLAG(&huart3, UART_FLAG_TC))
		{
			memset(reviceDat, 0, 200);
			return;
		}
	}
}
#else
void USER_UART_IDLECallback(UART_HandleTypeDef *huart)
{
	
}

void USER_UART3_IDLECallback(UART_HandleTypeDef *huart)
{
	
}
#endif

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
  // printf("DMA data len %d : \r\n", Size);
  // for (size_t i = 0; i < Size; i++)
  // {
  //   printf("%2x ", reviceDmaDat[i]);
  // }
  // printf("\r\n");
  usrAddAck((char*)reviceDmaDat, Size);
  memset(reviceDmaDat, 0, USR_RX_DMA_LEN_MAX);
  HAL_UARTEx_ReceiveToIdle_DMA(&huart3, reviceDmaDat, USR_RX_DMA_LEN_MAX);
  __HAL_DMA_DISABLE_IT(&hdma_usart3_rx, DMA_IT_HT);
}

void app_timer2_period(TIM_HandleTypeDef *htim)
{
  // printf("time3 is break\r\n");
  timer2Flag = 1;
}

void app_timer3_period(TIM_HandleTypeDef *htim)
{
  // printf("time4 is break\r\n");
  timer3Flag = 1;
}


#if 1
uint8_t usrAddCmd(char* p_dat, int len)
{
  return enqueue(&usrListTx, p_dat, len); 
}

void usrSendCmd(void)
{
  QueueElement* p_queue;
  p_queue = dequeue(&usrListTx);
  if(p_queue == 0)
  {
    return;
  }
  HAL_UART_Transmit_DMA(&huart3, (const uint8_t*)p_queue->data, p_queue->length);
  // HAL_Delay(5000);
}

uint8_t usrSendAt(char* p_dat, int len)
{
  // printf("send data %d :", len);
  // for (size_t i = 0; i < len; i++)
  // {
  //   printf(" %2x", p_dat[i]);
  // }
  // printf("\r\n");

  if (HAL_UART_Transmit_DMA(&huart3, (const uint8_t*)p_dat, len) == HAL_OK)
    return USR_SUCCESS;
  else
    return USR_AT_CMD_SEND_ERROR;
}

uint8_t usrAddAck(char* p_dat, int len)
{
  int i;
  for (i = 0; i + MAX_ELEMENT_SIZE <= len; i += MAX_ELEMENT_SIZE)
  {
    if(enqueue(&usrListRx, p_dat + i, MAX_ELEMENT_SIZE) != USR_SUCCESS)
      return USR_ACK_RECV_ERROR;
  }

  return enqueue(&usrListRx, p_dat + i, len - i); 
}

uint8_t usrHandleAck(char* p_dat, int* p_len)
{
  QueueElement* p_queue;
  p_queue = dequeue(&usrListRx);
  if(p_queue == 0)
  {
    return USR_LIST_EMPTY;
  }
  
  // printf("recv data %d :", p_queue->length);
  // for (size_t i = 0; i < p_queue->length; i++)
  // {
  //   printf(" %2x", p_queue->data[i]);
  // }
  // printf("\r\n");


  if (p_dat == NULL || p_len == NULL)
  {
    return USR_PARAM_ERROR;
  }
  for (size_t i = 0; i < p_queue->length; i++)
  {
    p_dat[i] = p_queue->data[i];
  }
  *p_len = p_queue->length;

  return USR_SUCCESS;
}

void usrDeviceInit(void)
{
  wifiConfig_t config1 = {.pwd = USR_WIFI_PWD, .ssid = USR_WIFI_SSID};
  tcpConfig_t  config2 = {.ip  = USR_IP, .port = USR_PORT};


  if(usrSendAtCmd(AT_CMD_TEST, NULL, 0) != USR_SUCCESS)
    printf("AT transmission error\r\n");

  if(usrSendAtCmd(AT_CMD_GMR, NULL, 0) != USR_SUCCESS)
    printf("GET AT vision error\r\n");

  if(usrSendAtCmd(AT_CMD_CWMODE, NULL, 0) != USR_SUCCESS)
    printf("set wifi mode error\r\n");

  if(usrSendAtCmd(AT_CMD_CWJAP, (char*)(&config1), 0) != USR_SUCCESS)
    printf("device connect wifi ap error\r\n");

  if(usrSendAtCmd(AT_CMD_CIFSR, NULL, 0) != USR_SUCCESS)
    printf("device get ip error\r\n");
  
  if(usrSendAtCmd(AT_CMD_CIPSTART, (char*)(&config2), 0) != USR_SUCCESS)
    printf("device connect tcp %s %d error\r\n", config2.ip, config2.port);

  if(usrSendAtCmd(AT_CMD_CIPMODE, NULL, 0) != USR_SUCCESS)
    printf("device cip init error\r\n");

  if(usrSendAtCmd(AT_CMD_CIPSEND, NULL, 0) != USR_SUCCESS)
    printf("device cip start error\r\n");

  HAL_Delay(1000);
}

void usrPublishCallback(void** unused, struct mqtt_response_publish *published)
{
  printf("-------------usrPublishCallback-----------------\r\n");
  char* topic_name = (char*) malloc(published->topic_name_size + 1);
  memcpy(topic_name, published->topic_name, published->topic_name_size);
  topic_name[published->topic_name_size] = '\0';
  printf("Received publish('%s'): %s\n", topic_name, (const char*) published->application_message);
  free(topic_name);
}
void usrResponseCallback(int responseType)
{
  switch (responseType)
  {
  case MQTT_CONTROL_CONNACK:
    if(client.error == MQTT_OK)
      usrMqttStatus = USR_MQTT_STATE_CONNECTED;
    break;
  case MQTT_CONTROL_SUBACK:
    if(client.error == MQTT_OK)
      usrMqttStatus = USR_MQTT_STATE_SUBACK;
    break;
  
  default:
    break;
  }
}

void usrMqttStatusFirm(void)
{
  switch (usrMqttStatus)
  {
  case USR_MQTT_STATE_CONNECTED:
    mqtt_subscribe(&client, USR_MQTT_SUB_TOPIC, 0);
    usrMqttStatus = 0;
    break;

  case  USR_MQTT_STATE_SUBACK:
    mqtt_publish(&client, USR_MQTT_PUB_TOPIC, test, strlen(test) + 1, MQTT_PUBLISH_QOS_0);
    break;
  
  default:
    break;
  }
}

void usrMqttInit(void)
{
  /* setup a client */
  int ret;
  mqtt_pal_socket_handle sockfd;

  ret = mqtt_init(&client, sockfd, sendbuf, sizeof(sendbuf), recvbuf, sizeof(recvbuf), usrPublishCallback);
  if(ret != MQTT_OK)
    printf("mqtt init error %d\r\n", ret);
  /* Create an anonymous session */
  const char* client_id = USR_CLIENT_ID;
  const char* usrName   = USR_NAME;
  const char* usrpwd    = USR_PWD;
  client.usr_response_callback = usrResponseCallback;
  /* Ensure we have a clean session */
  uint8_t connect_flags = MQTT_CONNECT_PASSWORD | MQTT_CONNECT_USER_NAME;
  /* Send connection request to the broker. */
  ret = mqtt_connect(&client, client_id, NULL, NULL, 0, usrName, usrpwd, connect_flags, 60);
  if(ret != MQTT_OK)
    printf("mqtt connect error %d\r\n", ret);

  HAL_TIM_Base_Start_IT(&htim2);
}

void usrMqttcycle(void)
{
  int ret;
  ret = mqtt_sync((struct mqtt_client*) &client);
  if(ret != MQTT_OK)
    printf("mqtt sync error %d\r\n", ret);
}
#endif

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */
  usrAtInit(usrSendAt, usrHandleAck);
  usrQueueInit(&usrListTx);
  usrQueueInit(&usrListRx);
  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_DMA_Init();
  MX_USART3_UART_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  /* USER CODE BEGIN 2 */
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_SET);
	HAL_Delay(3000);
	
  #if AT_TEST
	HAL_UART_RegisterCallback(&huart1, HAL_UART_RX_COMPLETE_CB_ID, app_uart_cb);
	HAL_UART_RegisterCallback(&huart3, HAL_UART_TX_COMPLETE_CB_ID, app_uart3_tx_cb);
  #endif

  HAL_TIM_RegisterCallback(&htim2, HAL_TIM_PERIOD_ELAPSED_CB_ID, app_timer2_period);
  HAL_TIM_RegisterCallback(&htim3, HAL_TIM_PERIOD_ELAPSED_CB_ID, app_timer3_period);

  #if AT_TEST
	HAL_UART_Receive_IT(&huart1,(uint8_t*)&reviceTmp,1);
	__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);
  #endif

	HAL_UARTEx_ReceiveToIdle_DMA(&huart3, reviceDmaDat, USR_RX_DMA_LEN_MAX);
  __HAL_DMA_DISABLE_IT(&hdma_usart3_rx, DMA_IT_HT);
	
	printf("HELLO WORLD!!\r\n");

  usrDeviceInit();
  printf("start mqtt \r\n");
  usrMqttInit();
  HAL_TIM_Base_Start_IT(&htim3);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
    // HAL_Delay(3000);
    if(timer2Flag)
    { 
      timer2Flag = 0;
      usrMqttcycle();
    }
    if(timer3Flag)
    {
      timer3Flag = 0;
      usrMqttStatusFirm();
    }
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
